﻿#include "screen.h"
#include "wndhelper.h"

#include <QPainter>
#include <QMouseEvent>
#include <QPainterPath>
#include <QPoint>
#include <QDebug>
#include <QScreen>
#include <QGuiApplication>
#include <QFileDialog>
#include <QRectF>
#include "controlwidget.h"
#include <QHBoxLayout>
#include <QPushButton>
#include <QTime>
#include <QApplication>
#include <QDesktopWidget>
#include <QWindow>
#include <QDebug>
#include <QClipboard>

#include <memory>

#ifdef Q_OS_WIN32
#include <windows.h>
#include <Dwmapi.h>
#elif defined Q_OS_MAC

#endif

#include"myrect.h"

QString getSavePath() {
    //生成图片名称
    static QString lastSelectDir = "";
    QString picName;
    QTime time;
    //获取当前系统时间，用做伪随机数的种子
    time = QTime::currentTime();
    qsrand(time.msec() + time.second() * 1000);
    //随机字符串
    QString randStr;
    randStr.setNum(qrand());
    picName.append(randStr);

    QString filename = QFileDialog::getSaveFileName(nullptr,QStringLiteral("保存截图"), lastSelectDir + picName,"JPEG Files(*.jpg)");
    if(!filename.isEmpty()){
        QFileInfo fileInfo(filename);
        lastSelectDir = fileInfo.absoluteDir().absolutePath() + "/";
    }
    return filename;
}

void Screen::Init()
{
    QScreen *scrPix = windowHandle()->screen();
    auto geometry = scrPix->geometry();

#ifdef Q_OS_MAC
    double ratio = 1.0;
#else
    double ratio = scrPix->devicePixelRatio();
#endif

    qDebug() << "Screen::Init()" << geometry << ratio;

    pixmap = scrPix->grabWindow(0,geometry.x(),geometry.y(),geometry.width()/ratio ,geometry.height()/ratio);

#ifdef Q_OS_MAC
    WndHelper::instance()->storeWndRectInfo();
#endif

    //全局路径的初始化，一个全屏闭合回路
    globalPath.lineTo(pixmap.width(), 0);
    globalPath.lineTo(pixmap.width(), pixmap.height());
    globalPath.lineTo(0, pixmap.height());
    globalPath.lineTo(0, 0);

    oncePress = true;
    isLeftPressed = false;

    setMouseTracking(true);

    //想到了添加一个bool labelimageShow()的函数的方法，找时间试一下
    labelimage=new QSLabel(this);
    labelimage->setOriginPixmap(pixmap);
    labelimage->setVisible(false);

    //显示尺寸的小窗口
    widthInfoRect.reset(new MyRect(this));
    amplifierRect.reset(new Amplifier(this));
    amplifierRect->setOriginPixmap(pixmap);

    controlUi = new ControlWidget();
    controlUi->setCanClip(false);

    connect(controlUi,&ControlWidget::drawRect,this,[=](){
        labelimage->setrectangleenable();
        pensetting->setSettingType(ST_NORMAL);
        pensetting->show();
    });

    connect(controlUi,&ControlWidget::drawLine,this,[=](){
        labelimage->setdrawlineenable();
        pensetting->setSettingType(ST_NORMAL);
        pensetting->show();
    });

    connect(controlUi,&ControlWidget::drawText,this,[=](){
        labelimage->settexteditenable();
        pensetting->setSettingType(ST_TEXT);
        pensetting->show();
    });


    connect(controlUi,&ControlWidget::drawArrow,this,[=](){
        labelimage->setdrawarrowenable();
        pensetting->setSettingType(ST_NORMAL);
        pensetting->show();
    });


    connect(controlUi,&ControlWidget::drawRound,this,[=](){
        labelimage->setroundenable();
        pensetting->setSettingType(ST_NORMAL);
        pensetting->show();
    });

    connect(controlUi,&ControlWidget::drawMosaic,this,[=](){
        labelimage->setdrawmosaicnable();
        pensetting->setSettingType(ST_MOSAIC);
        pensetting->show();
    });

    connect(controlUi,&ControlWidget::drawFace,this,[=](){
        labelimage->setdrawfacenable();
        pensetting->hide();
    });

    connect(controlUi,&ControlWidget::clip,this,[=](){
        labelimage->setclipable();
        pensetting->hide();
    });


    connect(controlUi,&ControlWidget::undo,this,[=](){
       labelimage->undo();
    });

    connect(controlUi,&ControlWidget::forward,this,[=](){
       doForward();
       close();
       Exit(3);
    });

    connect(controlUi,&ControlWidget::save,this,[=](){
        savePixmap();
        close();
        Exit(2);
    });

    connect(controlUi,&ControlWidget::cancel,this,[=](){
        close();
        Exit(1);
    });

    connect(controlUi,&ControlWidget::finish,this,[=](){
        complete();
    });

    updateSelectedWindow();
}

Screen::Screen(QWidget *parent)
    : QWidget(parent),
      widthInfoRect(nullptr),
      control(nullptr)
{
#ifdef Q_OS_WIN32
//    int ratio = scrPix->devicePixelRatio(); //2;
    double dpi = QApplication::primaryScreen()->logicalDotsPerInch();

    ratio = 1;
    if (dpi <= 108) { // 0-96-108
        ratio = 1;
    } else if (dpi <= 132) { // 108-120-132
        ratio = 1.25;
    } else if (dpi <= 168) { // 132-144-168
        ratio = 1.5;
    } else { // 168-192-inf
        ratio = 2;
    }
    qDebug() << "ratio: " << ratio << " dpi: " << dpi;
    Qt::WindowFlags nType = Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint | Qt::Tool;
#else
    Qt::WindowFlags nType =  ( Qt::Window | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint);
    ratio = 1;
#endif

    setWindowModality(Qt::ApplicationModal);
    setWindowFlags(nType);
    setAttribute(Qt::WA_TranslucentBackground, true);
    setAttribute(Qt::WA_DeleteOnClose,true); //窗口关闭时释放内存

    setContextMenuPolicy(Qt::NoContextMenu);
    setWindowTitle(QStringLiteral("截图"));

    pensetting = new PenSetting(this);
    pensetting->hide();
}

void Screen::paintEvent(QPaintEvent *e)//将上一个函数得到的全屏灰色图绘制在painter上，并添加宽高信息矩形和边角拖曳小正方形
{
    if(!this->isVisible())
        return;

    QPainter paint(this);
    paint.drawPixmap( rect(),pixmap);

    //初始化画笔操作
    QPen pen;
    pen.setColor(QColor(74,76,91));
    pen.setWidth(3);
    paint.setPen(pen);
    paint.setBrush(QColor(0, 0, 0, 100));

    //绘制阴影
    paint.drawPath(getPath());

    if (!m_highlightwindow.isEmpty()) { //绘制高亮
        QPen pen = paint.pen();
        pen.setColor(QColor(79,154,254));
        pen.setWidth(2);
        paint.setPen(pen);
        paint.setBrush(QColor(0,0,0,0));
        paint.drawRect(m_highlightwindow);
    }
}

//得到选区之外的路径
QPainterPath Screen::getPath()   //这个函数得到的是开始截图时候得到的白色选区
{
    if(oncePress && !m_highlightwindow.isEmpty()){
        QPainterPath path;
        path.addRect(m_highlightwindow);
        return globalPath.subtracted(path);
    }else if(isLeftPressed){
        //选取路径
        QPainterPath path;
        path.moveTo(pressedPoint.x(), pressedPoint.y());
        path.lineTo(movePoint.x(), pressedPoint.y());
        path.lineTo(movePoint.x(), movePoint.y());
        path.lineTo(pressedPoint.x(), movePoint.y());
        path.lineTo(pressedPoint.x(), pressedPoint.y());
        return globalPath.subtracted(path);
    }else {
        return globalPath;
    }
}

void Screen::mousePressEvent(QMouseEvent *e)
{
    if( e->button() == Qt::LeftButton)   //如果鼠标左键第一次按下
    {
        if(oncePress){
            pressedPoint = e->pos();
            movePoint = e->pos();
            widthInfoRect->show();
        }
        isLeftPressed = true;
        setFocus();
    }
    
    QWidget::mousePressEvent(e);
}

void Screen::updateControlPos(int topLeftX, int topLeftY,int bottomRightY, int bottomRightX)
{
    QScreen *scrPix = windowHandle()->screen();

    controlUi->setDpi(ratio);
    pensetting->setDpi(ratio);

    int controlW = CONTROL_WIDTH * ratio;
    int controlH = CONTROL_HEIGHT * ratio;
    int controlX = bottomRightX - controlW;
    int controlY = bottomRightY+ CONTROL_HEIGHTMARGIN;

    if(controlX + controlW >= this->width()){
        controlX = this->width() - controlW - 5;
    }

    if(controlX < 0){
        controlX = 5;
    }

    if(controlY + controlH > height() ){
        controlY = topLeftY - controlH - CONTROL_HEIGHTMARGIN;
    }

    if(controlY < 0){
        controlY = 5;
    }
    
    widthInfoRect->setText(tr("%1 * %2").arg(labelimage->width()).arg(labelimage->height()));
    widthInfoRect->setLocation(topLeftX, topLeftY);

    //control->setGeometry(controlX, controlY, controlW, controlH);
    //pensetting->setGeometry(controlX + 10,controlY,280 * ratio,30 *ratio);

    control->setGeometry(controlX, bottomRightY+ CONTROL_HEIGHTMARGIN, controlW, controlH);
    pensetting->setGeometry(controlX + 10,bottomRightY+10+controlH,280 * ratio,30 *ratio);
}

void Screen::mouseReleaseEvent(QMouseEvent *e)    //只有已经按下鼠标按键，才会存在鼠标释放行为，释放鼠标后会立刻出现控制面板
{
    if(e->button() == Qt::LeftButton){
        //连续两次左键 如果第一次操作了截图，则第二次点击截图外的其他地方不作任何处理
        //if(isLeftPressed == true && control /*&& !control->isHidden()*/){

       // }
      //  else
        if(oncePress)
        {
            oncePress = false;

            if(!m_highlightwindow.isEmpty()){
                labelimage->setGeometry(m_highlightwindow);
            }else{
                int wid = abs(movePoint.x() - pressedPoint.x());
                int hei = abs(movePoint.y() - pressedPoint.y());
                int x =  pressedPoint.x() < movePoint.x() ? pressedPoint.x() : movePoint.x();
                int y = pressedPoint.y() < movePoint.y() ? pressedPoint.y() : movePoint.y();

                labelimage->setGeometry(x, y,wid,hei);
            }

            this->grabImage();
            labelimage->show();

            amplifierRect->hide();

            if( !control )        //如果未出现截图操作控件
            {
                control = new QWidget(this);         //新建一个窗口控件
                QHBoxLayout *layout = new QHBoxLayout(control);    //在control上建立水平布局
                controlUi->setParent(control);
                layout->addWidget(controlUi);         //将控制窗口应用于水平布局
                layout->setContentsMargins(0, 0, 0, 0);
                control->setObjectName("control");
                control->setLayout(layout);
            }

            QRect labelRect = labelimage->geometry();

            //设置控制面板的位置
            updateControlPos(labelRect.left(), labelRect.top(), labelRect.bottom() , labelRect.right());

            control->show();

            //选区完成，应该显示label，清掉背景上画得矩形，否则拖动窗口时候矩形又被看到了。
            pressedPoint = {0,0};
            movePoint = {0,0};
            m_highlightwindow = {};
            update();
        }
    }
    else if(e->button() == Qt::RightButton){
        isLeftPressed = false;
        oncePress = true;

//        if(control && !control->isHidden()){
//            oldPoint = e->pos();
//            clearImagelable();
//            widthInfoRect->hide();
//            amplifierRect->show();
//            control->hide();
//            updateSelectedWindow();
//        }
//        else{
			Exit(1);
            close();
//        }
    }

    QWidget::mouseReleaseEvent(e);
}

void Screen::grabImage()
{
    auto lableRect = labelimage->geometry();
    qDebug() << "screenshot grab rect" << lableRect;

#ifdef Q_OS_MAC
    QScreen *scrPix = windowHandle()->screen();
    double ratio = scrPix->devicePixelRatio();
    QImage selectimage = pixmap.copy(lableRect.x()*ratio,lableRect.y()*ratio,lableRect.width()*ratio,lableRect.height()*ratio).toImage();
    //if(ratio != 1.0){ //Qt 5.12.0 use
    //    selectimage = selectimage.scaled(lableRect.size());
    //}

    qDebug() << "pixmapsize" << pixmap.size() <<"slectimage.size" << selectimage.size();
#else
    QImage selectimage = pixmap.copy(lableRect).toImage();
#endif

    labelimage->setimagetolabel(selectimage);
}

void Screen::doForward()
{
    QPixmap img = getGrabPixmap();
    emit forward(img);
}

void Screen::complete()
{
    QClipboard *board = QApplication::clipboard();
    QPixmap pix = getGrabPixmap();
    if(!pix.isNull()){
        board->setImage(pix.toImage());
    }

    close();
    Exit(0);
}

//void Screen::mouseDoubleClickEvent(QMouseEvent *event)
//{
//    qDebug() << "Screen::mouseDoubleClickEvent";
////    if(event->button() == Qt::LeftButton && !m_highlightwindow.isEmpty()){
////        labelimage->setGeometry(m_highlightwindow);
////        complete();
////    }
//}

void Screen::moveControls(){
    auto lableRect = labelimage->geometry();
    int bottomRightX = lableRect.bottomRight().x();
    int bottomRightY = lableRect.bottomRight().y();
    int topLeftX = lableRect.topLeft().x();
    int topLeftY = lableRect.topLeft().y();

    //设置控制面板的位置
    updateControlPos(topLeftX, topLeftY,bottomRightY, bottomRightX);
}

void Screen::mouseMoveEvent(QMouseEvent *e)
{
    QPoint tempPoint = e->pos();     //当前鼠标位置

    if(e->buttons() & Qt::LeftButton)   //如果左键按下
    {
        m_highlightwindow = {};

        if( oncePress )    //如果是第一次按下时候，
        {
            movePoint = e->pos();   //终点即为鼠标此时位置
            //此时的移动代表选区的变化

            widthInfoRect->show();
            //amplifierRect->show();
            //选取左上角的信息更改
            int x = qAbs(movePoint.x() - pressedPoint.x());//movepoint即终点坐标
            int y = qAbs(movePoint.y() - pressedPoint.y());

            widthInfoRect->setText(tr("%1 * %2").arg(x).arg(y));
            amplifierRect->setSizeInfo(tr("%1 * %2").arg(x).arg(y));
            if( comparePoint(pressedPoint, movePoint)) {
                widthInfoRect->setLocation(pressedPoint.x(), pressedPoint.y());
                amplifierRect->setLocation(movePoint.x(), movePoint.y());
            } else {
                widthInfoRect->setLocation(movePoint.x(), movePoint.y());
                amplifierRect->setLocation(movePoint.x(), movePoint.y());
            }
        }
//        else if( control ) { //如果控制面板已经出现，则第二次以后的每一次鼠标按键都会使其暂时隐藏
//            control->hide();
//        }
    }
    else{
        if(oncePress){ //非编辑状态检测窗口
            updateSelectedWindow();
        }

        setCursor(Qt::ArrowCursor);
        if(!control){
            amplifierRect->show();
            amplifierRect->setLocation(e->pos().x(), e->pos().y());
            amplifierRect->setSizeInfo(tr("%1 * %2").arg(e->pos().x()).arg(e->pos().y()));
        }
    }

    update();
    widthInfoRect->repaint();
}


void Screen::updateSelectedWindow(void) {
#ifdef Q_OS_WIN32
    /// 获取当前鼠标选中的窗口
    ::EnableWindow((HWND)winId(), FALSE);
    if( getSmallestWindowFromCursor(m_highlightwindow)){

        int ratio=QApplication::desktop()->devicePixelRatio();
        QPoint temp_pt = mapFromGlobal(QPoint(m_highlightwindow.x(), m_highlightwindow.y()));
        
        m_highlightwindow = QRect(temp_pt.x()/ratio, temp_pt.y()/ratio,
                                  m_highlightwindow.width()/ratio, m_highlightwindow.height()/ratio);

        ::EnableWindow((HWND)winId(), TRUE);
    }
#elif defined Q_OS_MAC
    getSmallestWindowFromCursor(m_highlightwindow);
#endif
}

bool Screen::getSmallestWindowFromCursor(QRect &windowRect) {
    return WndHelper::instance()->getSmallestWindowFromCursor(windowRect);
}

void Screen::keyPressEvent(QKeyEvent *e)    //键盘事件，包括esc退出截图，回车键完成截图，返回键完成截图
{
    int key = e->key();
    switch( key )
    {
    case Qt::Key_Escape :
		Exit(1);
        close();
        break;
    case Qt::Key_Enter:
        complete();
        break;
    case Qt::Key_Return :
        complete();
        break;
    default:
        break;
    }
}

PenSetting *Screen::getPensetting() const
{
    return pensetting;
}

void Screen::setUndoEnable(bool undoEnable)
{
    if(controlUi){
        controlUi->setReturnEnabled(undoEnable);
    }
}

void Screen::cancel()
{
    close();
    Exit(1);
}

bool Screen::close()
{
#ifdef Q_OS_MAC
    return WndHelper::instance()->closeWindow(this);
#else
    return QWidget::close();
#endif
}

//如果p1的x和y坐标都小于p2的x和y坐标返回true
bool Screen::comparePoint(QPoint &p1, QPoint &p2)      //点p1的位置坐标是否小于p2点
{
    if(p1.x() < p2.x() && p1.y() < p2.y())
        return true;
    return false;
}

void Screen::clearImagelable()
{
    labelimage->setGeometry(0,0,0,0);
    labelimage->hide();
}

//保存截取出来的图片
void Screen::savePixmap()
{
    QString filename = getSavePath();
    if(!filename.isEmpty()){
        QPixmap pimage=labelimage->resultimage();
        pimage.save(filename, "jpg");
    }
}

QPixmap Screen::getGrabPixmap()   //返回截到的图片
{
    return labelimage->resultimage();
}

void Screen::Exit(int code)
{
    hide();
    if(labelimage)
    {
        labelimage->close();
    }

    emit finished(code);
}

Screen::~Screen()
{
    qDebug() << "~Screen()";
}
